package com.haijing.highglass;

import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;

/**
 * Created by Administrator on 2016/6/17.
 */
public class HmdCtrl {
    private static final String TAG = "HmdCtrl";

    private static final byte COMM_SYNC_BEGIN = (byte) 0x55;
    private static final byte COMM_SYNC_END = (byte) 0xAA;

    private static final int COMM_LENGTH_MAX = 63;

    private static final int HMD_CTRL_CMD_GET_CONTRAST = 0x00;
    private static final int HMD_CTRL_CMD_SET_CONTRAST = 0x01;
    private static final int HMD_CTRL_CMD_GET_BRIGHTNESS = 0x02;
    private static final int HMD_CTRL_CMD_SET_BRIGHTNESS = 0x03;
    private static final int HMD_CTRL_CMD_GET_SATURATION = 0x04;
    private static final int HMD_CTRL_CMD_SET_SATURATION = 0x05;
    private static final int HMD_CTRL_CMD_GET_3D = 0x06;
    private static final int HMD_CTRL_CMD_SET_3D = 0x07;
    private static final int HMD_CTRL_CMD_GET_VIDEO_STATE = 0x08;
    private static final int HMD_CTRL_CMD_GET_GET_VERSION = 0x09;
    private static final int HMD_CTRL_CMD_GET_BRIGHTNESS_OFFSET = 0x0A;
    private static final int HMD_CTRL_CMD_SET_BRIGHTNESS_OFFSET = 0x0B;
    private static final int HMD_CTRL_CMD_GET_BRIGHTNESS_ABS = 0x0C;
    private static final int HMD_CTRL_CMD_SET_BRIGHTNESS_ABS = 0x0D;
    private static final int HMD_CTRL_CMD_UNLOCK_LCD = 0x0E;

    public static final byte HMD_CTRL_PARAM_DISP_3D_ERROR = (byte) 0xFF;
    public static final byte HMD_CTRL_PARAM_DISP_3D_NONE = (byte) 0x00;
    public static final byte HMD_CTRL_PARAM_DISP_3D_HALF_LR = (byte) 0x01;
    public static final byte HMD_CTRL_PARAM_DISP_3D_HALF_TB = (byte) 0x02;
    public static final byte HMD_CTRL_PARAM_DISP_3D_FULL = (byte) 0x03;

    public static final byte HMD_CTRL_PARAM_DISP_VIDEO_STATE_ERROR = (byte) 0xFF;
    public static final byte HMD_CTRL_PARAM_DISP_VIDEO_STATE_OFF = (byte) 0x00;
    public static final byte HMD_CTRL_PARAM_DISP_VIDEO_STATE_ON = (byte) 0x01;

    public static final byte HMD_CTRL_PARAM_DISP_BRIGHTNESS_OFFSET_ERROR = (byte)101;

    private static HmdContrast contrastGlobal = new HmdContrast();
    private static HmdBrightness brightnessGlobal = new HmdBrightness();
    private static HmdSaturation saturationGlobal = new HmdSaturation();

    static {
        System.loadLibrary("hmd-ctrl");
    }

    private native static int xfer(byte[] sendBuf, int sendCount, byte[] recvBuf, int recvCount);

    private static short calcChkSum(byte[] buffer, int byteOffset, int byteCount) {
        short chkSum = 0;
        int byteEnd;

        byteEnd = byteOffset + byteCount;
        for (int i = byteOffset; i < byteEnd; i++) {
            chkSum += (short) (buffer[i] & 0x00FF);
        }
        return chkSum;
    }

    private static int pack(byte[] packedBuf, int packedCount, byte[] payloadBuf, int payloadOffset, int payloadCount) {
        int index;
        short chkSum;

        if (packedCount < (payloadCount + 6)) {
            return -1;
        }

        index = 0;
        packedBuf[index] = COMM_SYNC_BEGIN;
        index++;
        packedBuf[index] = (byte) ((payloadCount & 0x0000FF00) >> 8);
        index++;
        packedBuf[index] = (byte) (payloadCount & 0x000000FF);
        index++;
        for (int i = 0; i < payloadCount; i++, index++) {
            packedBuf[index] = payloadBuf[payloadOffset + i];
        }
        chkSum = calcChkSum(packedBuf, 1, payloadCount + 2);
        packedBuf[index] = (byte) ((chkSum & 0xFF00) >> 8);
        index++;
        packedBuf[index] = (byte) (chkSum & 0x00FF);
        index++;
        packedBuf[index] = COMM_SYNC_END;
        index++;

        return index;
    }

    private static int unpack(byte[] packedBuf, int packedCount, byte[] payloadBuf, int payloadOffset, int payloadCount) {
        int index;
        short length;
        short chkSumRecv, chkSumCalc;

        index = 0;
        if (packedBuf[index] != COMM_SYNC_BEGIN) {
            return -1;
        }
        index++;
        length = (short) ((packedBuf[index] & 0x00FF) << 8);
        index++;
        length |= (short) (packedBuf[index] & 0x00FF);
        index++;
        if (packedCount != (length + 6)) {
            return -1;
        }
        if (payloadCount < length) {
            return -1;
        }
        for (int i = 0; i < length; i++, index++) {
            payloadBuf[payloadOffset + i] = packedBuf[index];
        }
        chkSumCalc = calcChkSum(packedBuf, 1, length + 2);

        chkSumRecv = (short) ((packedBuf[index] & 0x00FF) << 8);
        index++;
        chkSumRecv |= (short) (packedBuf[index] & 0x00FF);
        index++;

        if (chkSumRecv != chkSumCalc) {
            return -1;
        }
        if (packedBuf[index] != COMM_SYNC_END) {
            return -1;
        }

        return length;
    }

    private synchronized static int xferSync(byte[] sendBuf, int sendCount, byte[] recvBuf, int recvCount) {
        int ret;
        ret = xfer(sendBuf, sendCount, recvBuf, recvCount);
        return ret;
    }

    /**
     * set contrast.
     * tx : [cmd] [contrast.w] [contrast.r] [contrast.g] [contrast.b]
     * rx : [result] [contrast.w] [contrast.r] [contrast.g] [contrast.b]
     *
     * @param contrast HmdContrast to set
     * @return HmdContrast set
     */
    public static HmdContrast setContrast(HmdContrast contrast) {
        byte[] sendPackedBuf = new byte[COMM_LENGTH_MAX];
        int sendPackedCount;
        byte[] recvPackedBuf = new byte[COMM_LENGTH_MAX];
        int recvPackedCount;
        byte[] sendCmdBuf = new byte[COMM_LENGTH_MAX - 6];
        int sendCmdCount;
        byte[] recvCmdBuf = new byte[COMM_LENGTH_MAX - 6];
        int recvCmdCount;

        sendCmdCount = 0;
        sendCmdBuf[sendCmdCount] = HMD_CTRL_CMD_SET_CONTRAST;
        sendCmdCount++;
        sendCmdBuf[sendCmdCount] = (byte) contrast.w;
        sendCmdCount++;
        sendCmdBuf[sendCmdCount] = (byte) contrast.r;
        sendCmdCount++;
        sendCmdBuf[sendCmdCount] = (byte) contrast.g;
        sendCmdCount++;
        sendCmdBuf[sendCmdCount] = (byte) contrast.b;
        sendCmdCount++;

        sendPackedCount = pack(sendPackedBuf, sendPackedBuf.length, sendCmdBuf, 0, sendCmdCount);
        if (sendPackedCount < 0) {
            return null;
        }
        recvPackedCount = xferSync(sendPackedBuf, sendPackedCount, recvPackedBuf, recvPackedBuf.length);
        if (recvPackedCount < 0) {
            return null;
        }
        recvCmdCount = unpack(recvPackedBuf, recvPackedCount, recvCmdBuf, 0, recvCmdBuf.length);
        if (recvCmdCount < 0) {
            return null;
        }
        if (recvCmdBuf[0] != 0) {
            return null;
        }

        contrast.w = recvCmdBuf[1];
        contrast.r = recvCmdBuf[2];
        contrast.g = recvCmdBuf[3];
        contrast.b = recvCmdBuf[4];

        return contrast;
    }

    /**
     * get contrast.
     * tx : [cmd]
     * rx : [result] [contrast.w] [contrast.r] [contrast.g] [contrast.b]
     *
     * @return HmdContrast
     */
    public static HmdContrast getContrast() {
        byte[] sendPackedBuf = new byte[COMM_LENGTH_MAX];
        int sendPackedCount;
        byte[] recvPackedBuf = new byte[COMM_LENGTH_MAX];
        int recvPackedCount;
        byte[] sendCmdBuf = new byte[COMM_LENGTH_MAX - 6];
        int sendCmdCount;
        byte[] recvCmdBuf = new byte[COMM_LENGTH_MAX - 6];
        int recvCmdCount;

        sendCmdCount = 0;
        sendCmdBuf[sendCmdCount] = HMD_CTRL_CMD_GET_CONTRAST;
        sendCmdCount++;

        sendPackedCount = pack(sendPackedBuf, sendPackedBuf.length, sendCmdBuf, 0, sendCmdCount);
        if (sendPackedCount < 0) {
            return null;
        }
        recvPackedCount = xferSync(sendPackedBuf, sendPackedCount, recvPackedBuf, recvPackedBuf.length);
        if (recvPackedCount < 0) {
            return null;
        }
        recvCmdCount = unpack(recvPackedBuf, recvPackedCount, recvCmdBuf, 0, recvCmdBuf.length);
        if (recvCmdCount < 0) {
            return null;
        }
        if (recvCmdBuf[0] != 0) {
            return null;
        }

        HmdContrast contrast = new HmdContrast();
        contrast.w = recvCmdBuf[1];
        contrast.r = recvCmdBuf[2];
        contrast.g = recvCmdBuf[3];
        contrast.b = recvCmdBuf[4];

        return contrast;
    }

    /**
     * set brightness.
     * tx : [cmd] [brightness.w] [brightness.r] [brightness.g] [brightness.b]
     * rx : [result] [brightness.w] [brightness.r] [brightness.g] [brightness.b]
     *
     * @param brightness HmdBrightness to set
     * @return HmdBrightness set
     */
    public static HmdBrightness setBrightness(HmdBrightness brightness) {
        byte[] sendPackedBuf = new byte[COMM_LENGTH_MAX];
        int sendPackedCount;
        byte[] recvPackedBuf = new byte[COMM_LENGTH_MAX];
        int recvPackedCount;
        byte[] sendCmdBuf = new byte[COMM_LENGTH_MAX - 6];
        int sendCmdCount;
        byte[] recvCmdBuf = new byte[COMM_LENGTH_MAX - 6];
        int recvCmdCount;

        sendCmdCount = 0;
        sendCmdBuf[sendCmdCount] = HMD_CTRL_CMD_SET_BRIGHTNESS;
        sendCmdCount++;
        sendCmdBuf[sendCmdCount] = (byte) brightness.w;
        sendCmdCount++;
        sendCmdBuf[sendCmdCount] = (byte) brightness.r;
        sendCmdCount++;
        sendCmdBuf[sendCmdCount] = (byte) brightness.g;
        sendCmdCount++;
        sendCmdBuf[sendCmdCount] = (byte) brightness.b;
        sendCmdCount++;

        sendPackedCount = pack(sendPackedBuf, sendPackedBuf.length, sendCmdBuf, 0, sendCmdCount);
        if (sendPackedCount < 0) {
            return null;
        }
        recvPackedCount = xferSync(sendPackedBuf, sendPackedCount, recvPackedBuf, recvPackedBuf.length);
        if (recvPackedCount < 0) {
            return null;
        }
        recvCmdCount = unpack(recvPackedBuf, recvPackedCount, recvCmdBuf, 0, recvCmdBuf.length);
        if (recvCmdCount < 0) {
            return null;
        }
        if (recvCmdBuf[0] != 0) {
            return null;
        }

        brightness.w = recvCmdBuf[1];
        brightness.r = recvCmdBuf[2];
        brightness.g = recvCmdBuf[3];
        brightness.b = recvCmdBuf[4];

        return brightness;
    }

    /**
     * get brightness.
     * tx : [cmd]
     * rx : [result] [brightness.w] [brightness.r] [brightness.g] [brightness.b]
     *
     * @return HmdBrightness
     */
    public static HmdBrightness getBrightness() {
        byte[] sendPackedBuf = new byte[COMM_LENGTH_MAX];
        int sendPackedCount;
        byte[] recvPackedBuf = new byte[COMM_LENGTH_MAX];
        int recvPackedCount;
        byte[] sendCmdBuf = new byte[COMM_LENGTH_MAX - 6];
        int sendCmdCount;
        byte[] recvCmdBuf = new byte[COMM_LENGTH_MAX - 6];
        int recvCmdCount;

        sendCmdCount = 0;
        sendCmdBuf[sendCmdCount] = HMD_CTRL_CMD_GET_BRIGHTNESS;
        sendCmdCount++;

        sendPackedCount = pack(sendPackedBuf, sendPackedBuf.length, sendCmdBuf, 0, sendCmdCount);
        if (sendPackedCount < 0) {
            return null;
        }
        recvPackedCount = xferSync(sendPackedBuf, sendPackedCount, recvPackedBuf, recvPackedBuf.length);
        if (recvPackedCount < 0) {
            return null;
        }
        recvCmdCount = unpack(recvPackedBuf, recvPackedCount, recvCmdBuf, 0, recvCmdBuf.length);
        if (recvCmdCount < 0) {
            return null;
        }
        if (recvCmdBuf[0] != 0) {
            return null;
        }

        HmdBrightness brightness = new HmdBrightness();
        brightness.w = recvCmdBuf[1];
        brightness.r = recvCmdBuf[2];
        brightness.g = recvCmdBuf[3];
        brightness.b = recvCmdBuf[4];

        return brightness;
    }

    /**
     * set brightness absolutely. [1, 255]
     * tx : [cmd] [brightness.w] [brightness.r] [brightness.g] [brightness.b]
     * rx : [result] [brightness.w] [brightness.r] [brightness.g] [brightness.b]
     * @param brightness HmdBrightness to set
     * @return HmdBrightness set
     */
    public static HmdBrightness setBrightnessAbs(HmdBrightness brightness) {
        byte[] sendPackedBuf = new byte[COMM_LENGTH_MAX];
        int sendPackedCount;
        byte[] recvPackedBuf = new byte[COMM_LENGTH_MAX];
        int recvPackedCount;
        byte[] sendCmdBuf = new byte[COMM_LENGTH_MAX - 6];
        int sendCmdCount;
        byte[] recvCmdBuf = new byte[COMM_LENGTH_MAX - 6];
        int recvCmdCount;

        sendCmdCount = 0;
        sendCmdBuf[sendCmdCount] = HMD_CTRL_CMD_SET_BRIGHTNESS_ABS;
        sendCmdCount++;
        sendCmdBuf[sendCmdCount] = (byte) brightness.w;
        sendCmdCount++;
        sendCmdBuf[sendCmdCount] = (byte) brightness.r;
        sendCmdCount++;
        sendCmdBuf[sendCmdCount] = (byte) brightness.g;
        sendCmdCount++;
        sendCmdBuf[sendCmdCount] = (byte) brightness.b;
        sendCmdCount++;

        sendPackedCount = pack(sendPackedBuf, sendPackedBuf.length, sendCmdBuf, 0, sendCmdCount);
        if (sendPackedCount < 0) {
            Log.e(TAG, "pack error");
            return null;
        }
        recvPackedCount = xferSync(sendPackedBuf, sendPackedCount, recvPackedBuf, recvPackedBuf.length);
        if (recvPackedCount < 0) {
            Log.e(TAG, "xferSync error");
            return null;
        }
        recvCmdCount = unpack(recvPackedBuf, recvPackedCount, recvCmdBuf, 0, recvCmdBuf.length);
        if (recvCmdCount < 0) {
            Log.e(TAG, "unpack error");
            return null;
        }

        Log.d(TAG, "recv count : " + recvCmdCount);

        if (recvCmdBuf[0] != 0) {
            Log.e(TAG, "result error : " + recvCmdBuf[0]);
            return null;
        }

        brightness.w = recvCmdBuf[1] & 0xFF;
        brightness.r = recvCmdBuf[2] & 0xFF;
        brightness.g = recvCmdBuf[3] & 0xFF;
        brightness.b = recvCmdBuf[4] & 0xFF;

        return brightness;
    }

    /**
     * get brightness absolutely
     * tx : [cmd]
     * rx : [result] [brightness.w] [brightness.r] [brightness.g] [brightness.b]
     * @return HmdBrightness
     */
    public static HmdBrightness getBrightnessAbs() {
        byte[] sendPackedBuf = new byte[COMM_LENGTH_MAX];
        int sendPackedCount;
        byte[] recvPackedBuf = new byte[COMM_LENGTH_MAX];
        int recvPackedCount;
        byte[] sendCmdBuf = new byte[COMM_LENGTH_MAX - 6];
        int sendCmdCount;
        byte[] recvCmdBuf = new byte[COMM_LENGTH_MAX - 6];
        int recvCmdCount;

        sendCmdCount = 0;
        sendCmdBuf[sendCmdCount] = HMD_CTRL_CMD_GET_BRIGHTNESS_ABS;
        sendCmdCount++;

        sendPackedCount = pack(sendPackedBuf, sendPackedBuf.length, sendCmdBuf, 0, sendCmdCount);
        if (sendPackedCount < 0) {
            Log.e(TAG, "pack error");
            return null;
        }
        recvPackedCount = xferSync(sendPackedBuf, sendPackedCount, recvPackedBuf, recvPackedBuf.length);
        if (recvPackedCount < 0) {
            Log.e(TAG, "xferSync error");
            return null;
        }
        recvCmdCount = unpack(recvPackedBuf, recvPackedCount, recvCmdBuf, 0, recvCmdBuf.length);
        if (recvCmdCount < 0) {
            Log.e(TAG, "unpack error");
            return null;
        }

        Log.d(TAG, "recv count : " + recvCmdCount);

        if (recvCmdBuf[0] != 0) {
            Log.e(TAG, "result error : " + recvCmdBuf[0]);
            return null;
        }

        HmdBrightness brightness = new HmdBrightness();
        brightness.w = recvCmdBuf[1] & 0xFF;
        brightness.r = recvCmdBuf[2] & 0xFF;
        brightness.g = recvCmdBuf[3] & 0xFF;
        brightness.b = recvCmdBuf[4] & 0xFF;

        return brightness;
    }


    /**
     * set saturation.
     * tx : [cmd] [saturation.w] [saturation.r] [saturation.g] [saturation.b]
     * rx : [result] [saturation.w] [saturation.r] [saturation.g] [saturation.b]
     *
     * @param saturation HmdSaturation to set
     * @return HmdSaturation set
     */
    public static HmdSaturation setSaturation(HmdSaturation saturation) {
        byte[] sendPackedBuf = new byte[COMM_LENGTH_MAX];
        int sendPackedCount;
        byte[] recvPackedBuf = new byte[COMM_LENGTH_MAX];
        int recvPackedCount;
        byte[] sendCmdBuf = new byte[COMM_LENGTH_MAX - 6];
        int sendCmdCount;
        byte[] recvCmdBuf = new byte[COMM_LENGTH_MAX - 6];
        int recvCmdCount;

        sendCmdCount = 0;
        sendCmdBuf[sendCmdCount] = HMD_CTRL_CMD_SET_SATURATION;
        sendCmdCount++;
        sendCmdBuf[sendCmdCount] = (byte) saturation.w;
        sendCmdCount++;
        sendCmdBuf[sendCmdCount] = (byte) saturation.r;
        sendCmdCount++;
        sendCmdBuf[sendCmdCount] = (byte) saturation.g;
        sendCmdCount++;
        sendCmdBuf[sendCmdCount] = (byte) saturation.b;
        sendCmdCount++;

        sendPackedCount = pack(sendPackedBuf, sendPackedBuf.length, sendCmdBuf, 0, sendCmdCount);
        if (sendPackedCount < 0) {
            return null;
        }
        recvPackedCount = xferSync(sendPackedBuf, sendPackedCount, recvPackedBuf, recvPackedBuf.length);
        if (recvPackedCount < 0) {
            return null;
        }
        recvCmdCount = unpack(recvPackedBuf, recvPackedCount, recvCmdBuf, 0, recvCmdBuf.length);
        if (recvCmdCount < 0) {
            return null;
        }
        if (recvCmdBuf[0] != 0) {
            return null;
        }

        saturation.w = recvCmdBuf[1];
        saturation.r = recvCmdBuf[2];
        saturation.g = recvCmdBuf[3];
        saturation.b = recvCmdBuf[4];

        return saturation;
    }

    /**
     * get version.
     * tx : [cmd]
     * rx : [version[n -1]] ... [version[0]]
     * @return version string
     */
    public static String getVersion() {
        byte[] sendPackedBuf = new byte[COMM_LENGTH_MAX];
        int sendPackedCount;
        byte[] recvPackedBuf = new byte[COMM_LENGTH_MAX];
        int recvPackedCount;
        byte[] sendCmdBuf = new byte[COMM_LENGTH_MAX - 6];
        int sendCmdCount;
        byte[] recvCmdBuf = new byte[COMM_LENGTH_MAX - 6];
        int recvCmdCount;
        String version;

        sendCmdCount = 0;
        sendCmdBuf[sendCmdCount] = HMD_CTRL_CMD_GET_GET_VERSION;
        sendCmdCount++;

        sendPackedCount = pack(sendPackedBuf, sendPackedBuf.length, sendCmdBuf, 0, sendCmdCount);
        if (sendPackedCount < 0) {
            Log.e(TAG, "pack error");
            return null;
        }
        recvPackedCount = xferSync(sendPackedBuf, sendPackedCount, recvPackedBuf, recvPackedBuf.length);
        if (recvPackedCount < 0) {
            Log.e(TAG, "xferSync error");
            return null;
        }
        recvCmdCount = unpack(recvPackedBuf, recvPackedCount, recvCmdBuf, 0, recvCmdBuf.length);
        if (recvCmdCount < 0) {
            Log.e(TAG, "unpack error");
            return null;
        }

        Log.d(TAG, "recv count : " + recvCmdCount);

        if (recvCmdBuf[0] != 0) {
            Log.e(TAG, "result error : " + recvCmdBuf[0]);
            return null;
        }
        version = new String(recvCmdBuf, 1, recvCmdCount - 1);

        return version;
    }

    /**
     * set brightness offset : (<br right> - <br left>), range [-255, 255].
     * tx : [cmd] [brightness offset]
     * rx : [result] [brightness offset]
     * @param brightnessOffset to set
     * @return brightnessOffset set
     */
    public static int setBrightnessOffset(int brightnessOffset) {
        byte[] sendPackedBuf = new byte[COMM_LENGTH_MAX];
        int sendPackedCount;
        byte[] recvPackedBuf = new byte[COMM_LENGTH_MAX];
        int recvPackedCount;
        byte[] sendCmdBuf = new byte[COMM_LENGTH_MAX - 6];
        int sendCmdCount;
        byte[] recvCmdBuf = new byte[COMM_LENGTH_MAX - 6];
        int recvCmdCount;

        sendCmdCount = 0;
        sendCmdBuf[sendCmdCount] = HMD_CTRL_CMD_SET_BRIGHTNESS_OFFSET;
        sendCmdCount++;
        sendCmdBuf[sendCmdCount] = (byte)(brightnessOffset & 0xFF);
        sendCmdCount++;
        sendCmdBuf[sendCmdCount] = (byte)((brightnessOffset >> 8) & 0xFF);
        sendCmdCount++;
        sendCmdBuf[sendCmdCount] = (byte)((brightnessOffset >> 16) & 0xFF);
        sendCmdCount++;
        sendCmdBuf[sendCmdCount] = (byte)((brightnessOffset >> 24) & 0xFF);
        sendCmdCount++;

        sendPackedCount = pack(sendPackedBuf, sendPackedBuf.length, sendCmdBuf, 0, sendCmdCount);
        if (sendPackedCount < 0) {
            Log.e(TAG, "pack error");
            return HMD_CTRL_PARAM_DISP_BRIGHTNESS_OFFSET_ERROR;
        }
        recvPackedCount = xferSync(sendPackedBuf, sendPackedCount, recvPackedBuf, recvPackedBuf.length);
        if (recvPackedCount < 0) {
            Log.e(TAG, "xferSync error");
            return HMD_CTRL_PARAM_DISP_BRIGHTNESS_OFFSET_ERROR;
        }
        recvCmdCount = unpack(recvPackedBuf, recvPackedCount, recvCmdBuf, 0, recvCmdBuf.length);
        if (recvCmdCount < 0) {
            Log.e(TAG, "unpack error");
            return HMD_CTRL_PARAM_DISP_BRIGHTNESS_OFFSET_ERROR;
        }

        Log.d(TAG, "recv count : " + recvCmdCount);

        if (recvCmdBuf[0] != 0) {
            Log.e(TAG, "result error : " + recvCmdBuf[0]);
            return HMD_CTRL_PARAM_DISP_BRIGHTNESS_OFFSET_ERROR;
        }
        brightnessOffset = recvCmdBuf[1];
        brightnessOffset |= (recvCmdBuf[2] & 0xFF) << 8;
        brightnessOffset |= (recvCmdBuf[3] & 0xFF) << 16;
        brightnessOffset |= (recvCmdBuf[4] & 0xFF) << 24;

        return brightnessOffset;
    }

    /**
     * get brightness offset : (<br right> - <br left>), range [-255, 255].
     * tx : [cmd]
     * rx : [result] [brightness offset]
     * @return brightnessOffset
     */
    public static int getBrightnessOffset() {
        byte[] sendPackedBuf = new byte[COMM_LENGTH_MAX];
        int sendPackedCount;
        byte[] recvPackedBuf = new byte[COMM_LENGTH_MAX];
        int recvPackedCount;
        byte[] sendCmdBuf = new byte[COMM_LENGTH_MAX - 6];
        int sendCmdCount;
        byte[] recvCmdBuf = new byte[COMM_LENGTH_MAX - 6];
        int recvCmdCount;
        int brightnessOffset;

        sendCmdCount = 0;
        sendCmdBuf[sendCmdCount] = HMD_CTRL_CMD_GET_BRIGHTNESS_OFFSET;
        sendCmdCount++;

        sendPackedCount = pack(sendPackedBuf, sendPackedBuf.length, sendCmdBuf, 0, sendCmdCount);
        if (sendPackedCount < 0) {
            Log.e(TAG, "pack error");
            return HMD_CTRL_PARAM_DISP_BRIGHTNESS_OFFSET_ERROR;
        }
        recvPackedCount = xferSync(sendPackedBuf, sendPackedCount, recvPackedBuf, recvPackedBuf.length);
        if (recvPackedCount < 0) {
            Log.e(TAG, "xferSync error");
            return HMD_CTRL_PARAM_DISP_BRIGHTNESS_OFFSET_ERROR;
        }
        recvCmdCount = unpack(recvPackedBuf, recvPackedCount, recvCmdBuf, 0, recvCmdBuf.length);
        if (recvCmdCount < 0) {
            Log.e(TAG, "unpack error");
            return HMD_CTRL_PARAM_DISP_BRIGHTNESS_OFFSET_ERROR;
        }

        Log.d(TAG, "recv count : " + recvCmdCount);

        if (recvCmdBuf[0] != 0) {
            Log.e(TAG, "result error : " + recvCmdBuf[0]);
            return HMD_CTRL_PARAM_DISP_BRIGHTNESS_OFFSET_ERROR;
        }
        brightnessOffset = recvCmdBuf[1];
        brightnessOffset |= (recvCmdBuf[2] & 0xFF) << 8;
        brightnessOffset |= (recvCmdBuf[3] & 0xFF) << 16;
        brightnessOffset |= (recvCmdBuf[4] & 0xFF) << 24;

        return brightnessOffset;
    }

    /**
     * get saturation.
     * tx : [cmd]
     * rx : [result] [saturation.w] [saturation.r] [saturation.g] [saturation.b]
     *
     * @return HmdSaturation
     */
    public static HmdSaturation getSaturation() {
        byte[] sendPackedBuf = new byte[COMM_LENGTH_MAX];
        int sendPackedCount;
        byte[] recvPackedBuf = new byte[COMM_LENGTH_MAX];
        int recvPackedCount;
        byte[] sendCmdBuf = new byte[COMM_LENGTH_MAX - 6];
        int sendCmdCount;
        byte[] recvCmdBuf = new byte[COMM_LENGTH_MAX - 6];
        int recvCmdCount;

        sendCmdCount = 0;
        sendCmdBuf[sendCmdCount] = HMD_CTRL_CMD_GET_SATURATION;
        sendCmdCount++;

        sendPackedCount = pack(sendPackedBuf, sendPackedBuf.length, sendCmdBuf, 0, sendCmdCount);
        if (sendPackedCount < 0) {
            return null;
        }
        recvPackedCount = xferSync(sendPackedBuf, sendPackedCount, recvPackedBuf, recvPackedBuf.length);
        if (recvPackedCount < 0) {
            return null;
        }
        recvCmdCount = unpack(recvPackedBuf, recvPackedCount, recvCmdBuf, 0, recvCmdBuf.length);
        if (recvCmdCount < 0) {
            return null;
        }
        if (recvCmdBuf[0] != 0) {
            return null;
        }

        HmdSaturation saturation = new HmdSaturation();
        saturation.w = recvCmdBuf[1];
        saturation.r = recvCmdBuf[2];
        saturation.g = recvCmdBuf[3];
        saturation.b = recvCmdBuf[4];

        return saturation;
    }

    /**
     * set 3D mode.
     * tx : [cmd] [mode]
     * rx : [result]
     *
     * @return mode set
     */
    public static byte set3D(byte mode) {
        byte[] sendPackedBuf = new byte[COMM_LENGTH_MAX];
        int sendPackedCount;
        byte[] recvPackedBuf = new byte[COMM_LENGTH_MAX];
        int recvPackedCount;
        byte[] sendCmdBuf = new byte[COMM_LENGTH_MAX - 6];
        int sendCmdCount;
        byte[] recvCmdBuf = new byte[COMM_LENGTH_MAX - 6];
        int recvCmdCount;

        sendCmdCount = 0;
        sendCmdBuf[sendCmdCount] = HMD_CTRL_CMD_SET_3D;
        sendCmdCount++;
        sendCmdBuf[sendCmdCount] = mode;
        sendCmdCount++;

        int screenMode = 1;
        if (mode == HMD_CTRL_PARAM_DISP_3D_NONE) {
            screenMode = 1;
        } else if (mode == HMD_CTRL_PARAM_DISP_3D_HALF_LR) {
            screenMode = 2;
        }
        try {
            IBinder flinger = ServiceManager.getService("SurfaceFlinger");
            if (flinger != null) {
                Parcel data = Parcel.obtain();
                data.writeInterfaceToken("android.ui.ISurfaceComposer");
                data.writeInt(screenMode); // 1:2D content, 2:3D content.
                data.writeFloat(0.95f); // scale, default 0.95
                flinger.transact(1017, data, null, 0);//1019 0 非全屏 1全屏 1020 读取
                data.recycle();
            }else{
            }
        } catch (RemoteException ex) {
        }
        sendPackedCount = pack(sendPackedBuf, sendPackedBuf.length, sendCmdBuf, 0, sendCmdCount);
        if (sendPackedCount < 0) {
            return HMD_CTRL_PARAM_DISP_3D_ERROR;
        }
        recvPackedCount = xferSync(sendPackedBuf, sendPackedCount, recvPackedBuf, recvPackedBuf.length);
        if (recvPackedCount < 0) {
            return HMD_CTRL_PARAM_DISP_3D_ERROR;
        }
        recvCmdCount = unpack(recvPackedBuf, recvPackedCount, recvCmdBuf, 0, recvCmdBuf.length);
        if (recvCmdCount < 0) {
            return HMD_CTRL_PARAM_DISP_3D_ERROR;
        }


        if (recvCmdBuf[0] != 0) {
            return HMD_CTRL_PARAM_DISP_3D_ERROR;
        }

        return mode;
    }

    /**
     * set 3D mode.
     * tx : [cmd] [mode]
     * rx : [result]
     *
     * @return mode set
     */
    public static byte unlock_lcd() {
        byte[] sendPackedBuf = new byte[COMM_LENGTH_MAX];
        int sendPackedCount;
        byte[] recvPackedBuf = new byte[COMM_LENGTH_MAX];
        int recvPackedCount;
        byte[] sendCmdBuf = new byte[COMM_LENGTH_MAX - 6];
        int sendCmdCount;
        byte[] recvCmdBuf = new byte[COMM_LENGTH_MAX - 6];
        int recvCmdCount;

        sendCmdCount = 0;
        sendCmdBuf[sendCmdCount] = HMD_CTRL_CMD_UNLOCK_LCD;
        sendCmdCount++;

        sendPackedCount = pack(sendPackedBuf, sendPackedBuf.length, sendCmdBuf, 0, sendCmdCount);
        if (sendPackedCount < 0) {
            return HMD_CTRL_PARAM_DISP_3D_ERROR;
        }
        recvPackedCount = xferSync(sendPackedBuf, sendPackedCount, recvPackedBuf, recvPackedBuf.length);
        if (recvPackedCount < 0) {
            return HMD_CTRL_PARAM_DISP_3D_ERROR;
        }

        return 0x00;
    }

    /**
     * get 3D mode.
     * tx : [cmd]
     * rx : [result] [mode]
     *
     * @return 3D mode
     */
    public static byte get3D() {
        try {
            File file = new File("/sys/class/display/HDMI/monitor_name");
            FileInputStream inputStream = new FileInputStream(file);
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
            String line = bufferedReader.readLine();
            inputStream.close();
            if (line.contains("Toshiba-UH2D")) {
                IBinder flinger = ServiceManager.getService("SurfaceFlinger");
                if (flinger != null) {
                    Parcel data = Parcel.obtain();
                    Parcel reply = Parcel.obtain();
                    data.writeInterfaceToken("android.ui.ISurfaceComposer");
                    flinger.transact(1018, data, reply, 0);
                    data.recycle();
                    int mode = reply.readInt();
                    if (mode == 1) {
                        return HMD_CTRL_PARAM_DISP_3D_NONE;
                    } else if (mode == 2) {
                        return HMD_CTRL_PARAM_DISP_3D_HALF_LR;
                    }
                    return HMD_CTRL_PARAM_DISP_3D_ERROR;
                }
            }
        } catch (Exception e) {
            return HMD_CTRL_PARAM_DISP_3D_ERROR;
        }

        byte[] sendPackedBuf = new byte[COMM_LENGTH_MAX];
        int sendPackedCount;
        byte[] recvPackedBuf = new byte[COMM_LENGTH_MAX];
        int recvPackedCount;
        byte[] sendCmdBuf = new byte[COMM_LENGTH_MAX - 6];
        int sendCmdCount;
        byte[] recvCmdBuf = new byte[COMM_LENGTH_MAX - 6];
        int recvCmdCount;

        sendCmdCount = 0;
        sendCmdBuf[sendCmdCount] = HMD_CTRL_CMD_GET_3D;
        sendCmdCount++;

        sendPackedCount = pack(sendPackedBuf, sendPackedBuf.length, sendCmdBuf, 0, sendCmdCount);
        if (sendPackedCount < 0) {
            return HMD_CTRL_PARAM_DISP_3D_ERROR;
        }
        recvPackedCount = xferSync(sendPackedBuf, sendPackedCount, recvPackedBuf, recvPackedBuf.length);
        if (recvPackedCount < 0) {
            return HMD_CTRL_PARAM_DISP_3D_ERROR;
        }
        recvCmdCount = unpack(recvPackedBuf, recvPackedCount, recvCmdBuf, 0, recvCmdBuf.length);
        if (recvCmdCount < 0) {
            return HMD_CTRL_PARAM_DISP_3D_ERROR;
        }


        if (recvCmdBuf[0] != 0) {
            return HMD_CTRL_PARAM_DISP_3D_ERROR;
        }

        return recvCmdBuf[1];
    }

    /**
     * get video state.
     * tx : [cmd]
     * rx : [result] [state]
     *
     * @return video state
     */
    public static byte getVideoState() {
        byte[] sendPackedBuf = new byte[COMM_LENGTH_MAX];
        int sendPackedCount;
        byte[] recvPackedBuf = new byte[COMM_LENGTH_MAX];
        int recvPackedCount;
        byte[] sendCmdBuf = new byte[COMM_LENGTH_MAX - 6];
        int sendCmdCount;
        byte[] recvCmdBuf = new byte[COMM_LENGTH_MAX - 6];
        int recvCmdCount;

        sendCmdCount = 0;
        sendCmdBuf[sendCmdCount] = HMD_CTRL_CMD_GET_VIDEO_STATE;
        sendCmdCount++;

        sendPackedCount = pack(sendPackedBuf, sendPackedBuf.length, sendCmdBuf, 0, sendCmdCount);
        if (sendPackedCount < 0) {
            return HMD_CTRL_PARAM_DISP_VIDEO_STATE_ERROR;
        }
        recvPackedCount = xferSync(sendPackedBuf, sendPackedCount, recvPackedBuf, recvPackedBuf.length);
        if (recvPackedCount < 0) {
            return HMD_CTRL_PARAM_DISP_VIDEO_STATE_ERROR;
        }
        recvCmdCount = unpack(recvPackedBuf, recvPackedCount, recvCmdBuf, 0, recvCmdBuf.length);
        if (recvCmdCount < 0) {
            return HMD_CTRL_PARAM_DISP_VIDEO_STATE_ERROR;
        }
        if (recvCmdBuf[0] != 0) {
            return HMD_CTRL_PARAM_DISP_VIDEO_STATE_ERROR;
        }

        return recvCmdBuf[1];
    }

    public static boolean isBigScreen() {
        try {
            File file = new File("/sys/class/display/HDMI/monitor_name");
            FileInputStream inputStream = new FileInputStream(file);
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
            String line = bufferedReader.readLine();
            inputStream.close();
            if (line.contains("Toshiba-UH2D")) {
                return true;
            }
        } catch (Exception e) {
        }
        return false;
    }

    public static void openVR(int openVR){
        // 0 非全屏 1全屏 1020 读取
//        try {
//            IBinder flinger = ServiceManager.getService("SurfaceFlinger");
//            if (flinger != null) {
//                Parcel data = Parcel.obtain();
//                data.writeInterfaceToken("android.ui.ISurfaceComposer");
//                data.writeInt(openVR); // 1:2D content, 2:3D content.
//                data.writeFloat(0.95f); // scale, default 0.95
//                flinger.transact(1019, data, null, 0);//1019 0 非全屏 1全屏 1020 读取
//                data.recycle();
//            }
//        } catch (RemoteException ex) {
//        }
    }
}
